package main

import (
	"database/sql"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

// 服务器信息结构体
type Server struct {
	ID          uint      `json:"id" gorm:"primaryKey"`
	Name        string    `json:"name" gorm:"uniqueIndex;size:255;not null;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"`
	IP          string    `json:"ip" gorm:"uniqueIndex;size:50;not null;type:varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"`
	Hostname    string    `json:"hostname" gorm:"size:255;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"`
	OS          string    `json:"os" gorm:"size:100;type:varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"`
	CPU         string    `json:"cpu" gorm:"size:100;type:varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"`
	Memory      int       `json:"memory"` // GB
	Disk        int       `json:"disk"`   // GB
	Status      string    `json:"status" gorm:"size:20;type:varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"` // running, stopped, maintenance
	DeployTime  time.Time `json:"deploy_time"`
	LastCheckin time.Time `json:"last_checkin"`
	CreatedAt   time.Time `json:"created_at" gorm:"autoCreateTime"`
	UpdatedAt   time.Time `json:"updated_at" gorm:"autoUpdateTime"`
}

// 数据库实例
var db *gorm.DB
var sqlDB *sql.DB

// 数据库操作方式控制变量：false使用gorm，true使用原生SQL
var useRawSQL = false

func main() {
	// 初始化数据库连接
	initDB()

	// 初始化Gin路由
	r := gin.Default()

	// 添加CORS中间件
	r.Use(corsMiddleware())

	// 路由配置
	api := r.Group("/api")
	{
		// 服务器管理相关路由
		servers := api.Group("/servers")
		{
			servers.GET("", getServers)          // 获取服务器列表
			servers.POST("", createServer)       // 创建新服务器
			servers.GET("/:id", getServer)       // 获取单个服务器详情
			servers.PUT("/:id", updateServer)    // 更新服务器信息
			servers.DELETE("/:id", deleteServer) // 删除服务器
		}

		// 健康检查
		api.GET("/health", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"status": "ok", "time": time.Now(), "db_mode": "gorm"})
		})

		// 切换数据库操作模式
		api.POST("/toggle-db-mode", func(c *gin.Context) {
			var request struct {
				UseRawSQL bool `json:"use_raw_sql"`
			}

			if err := c.ShouldBindJSON(&request); err != nil {
				c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
				return
			}

			useRawSQL = request.UseRawSQL
			mode := "gorm"
			if useRawSQL {
				mode = "raw_sql"
			}

			c.JSON(http.StatusOK, gin.H{
				"message": "数据库操作模式已切换",
				"current_mode": mode,
				"use_raw_sql": useRawSQL,
			})
		})
	}

	// 启动服务器
	serverAddr := ":8080"
	fmt.Printf("服务器启动成功，监听地址: http://localhost%s\n", serverAddr)
	if err := r.Run(serverAddr); err != nil {
		log.Fatalf("服务器启动失败: %v", err)
	}
}

// 初始化数据库连接
func initDB() {
	// 连接默认数据库
	dsnDefault := "root:rootpassword@tcp(172.16.200.102:3306)/mysql?charset=utf8mb4&parseTime=True&loc=Local&collation=utf8mb4_unicode_ci"
	var err error

	// 连接默认数据库
	defaultDB, err := gorm.Open(mysql.Open(dsnDefault), &gorm.Config{})
	if err != nil {
		log.Fatalf("无法连接到MySQL默认数据库: %v", err)
	}

	// 创建cmdb数据库
	if err = defaultDB.Exec("CREATE DATABASE IF NOT EXISTS cmdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci").Error; err != nil {
		log.Fatalf("创建cmdb数据库失败: %v", err)
	}
	log.Println("cmdb数据库创建成功")

	// 关闭默认连接
	sqlDB, _ := defaultDB.DB()
	sqlDB.Close()

	// 连接到cmdb数据库，确保使用正确的字符集
	dsn := "root:rootpassword@tcp(172.16.200.102:3306)/cmdb?charset=utf8mb4&parseTime=True&loc=Local&collation=utf8mb4_unicode_ci"
	
	// 配置GORM选项，优化连接设置
	config := &gorm.Config{
		PrepareStmt: true,
	}
	db, err = gorm.Open(mysql.Open(dsn), config)
	if err != nil {
		log.Fatalf("无法连接到cmdb数据库: %v", err)
	}
	
	// 获取底层sql.DB以配置连接池和字符集
	sqlDB, err = db.DB()
	if err != nil {
		log.Fatalf("无法获取数据库实例: %v", err)
	}
	
	// 设置连接池参数
	sqlDB.SetMaxIdleConns(10)
	sqlDB.SetMaxOpenConns(100)
	
	// 确保连接使用utf8mb4字符集
	if _, err := sqlDB.Exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"); err != nil {
		log.Printf("警告: 设置字符集失败: %v", err)
	}

	log.Println("成功连接到cmdb数据库")

	// 不再删除表，保留现有数据
	log.Println("保留现有表结构，进行自动迁移")
	
	// 确保连接使用utf8mb4字符集
	if err := db.Exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci").Error; err != nil {
		log.Printf("警告: 迁移前设置字符集失败: %v", err)
	}

	// 自动迁移数据库表结构，使用新的字符集设置
	err = db.AutoMigrate(&Server{})
	if err != nil {
		log.Fatalf("数据库迁移失败: %v", err)
	}

	// 迁移完成后再次确保字符集设置
	if err := db.Exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci").Error; err != nil {
		log.Printf("警告: 迁移后设置字符集失败: %v", err)
	}

	log.Println("数据库表结构迁移完成")

	// 插入一些测试数据（如果表为空）
	var count int64
	db.Model(&Server{}).Count(&count)
	if count == 0 {
		// 创建测试数据
		testServers := []Server{
			{
				Name:        "web-server-01",
				IP:          "192.168.1.101",
				Hostname:    "web-01.example.com",
				OS:          "Ubuntu 20.04 LTS",
				CPU:         "4核心",
				Memory:      8,
				Disk:        200,
				Status:      "running",
				DeployTime:  time.Now().AddDate(0, -1, 0),
				LastCheckin: time.Now(),
			},
			{
				Name:        "db-server-01",
				IP:          "192.168.1.102",
				Hostname:    "db-01.example.com",
				OS:          "CentOS 8",
				CPU:         "8核心",
				Memory:      32,
				Disk:        2000,
				Status:      "running",
				DeployTime:  time.Now().AddDate(0, -2, 0),
				LastCheckin: time.Now(),
			},
			{
				Name:        "app-server-01",
				IP:          "192.168.1.103",
				Hostname:    "app-01.example.com",
				OS:          "Debian 10",
				CPU:         "4核心",
				Memory:      16,
				Disk:        500,
				Status:      "stopped",
				DeployTime:  time.Now().AddDate(0, -3, 0),
				LastCheckin: time.Now().Add(-24 * time.Hour),
			},
			{
				Name:        "api-server-01",
				IP:          "192.168.1.104",
				Hostname:    "api-01.example.com",
				OS:          "Ubuntu 22.04 LTS",
				CPU:         "16核心",
				Memory:      64,
				Disk:        1000,
				Status:      "running",
				DeployTime:  time.Now().AddDate(0, 0, -15),
				LastCheckin: time.Now(),
			},
			{
				Name:        "cache-server-01",
				IP:          "192.168.1.105",
				Hostname:    "cache-01.example.com",
				OS:          "Alpine Linux 3.18",
				CPU:         "8核心",
				Memory:      128,
				Disk:        200,
				Status:      "maintenance",
				DeployTime:  time.Now().AddDate(0, -2, -10),
				LastCheckin: time.Now().Add(-48 * time.Hour),
			},
			{
				Name:        "monitor-server-01",
				IP:          "192.168.1.106",
				Hostname:    "monitor-01.example.com",
				OS:          "Rocky Linux 9",
				CPU:         "8核心",
				Memory:      16,
				Disk:        500,
				Status:      "running",
				DeployTime:  time.Now().AddDate(0, -1, 20),
				LastCheckin: time.Now(),
			},
			{
				Name:        "backup-server-01",
				IP:          "192.168.1.107",
				Hostname:    "backup-01.example.com",
				OS:          "CentOS Stream 9",
				CPU:         "16核心",
				Memory:      32,
				Disk:        4000,
				Status:      "stopped",
				DeployTime:  time.Now().AddDate(0, -4, 0),
				LastCheckin: time.Now().Add(-7 * 24 * time.Hour),
			},
		}

		for _, server := range testServers {
			if err := db.Create(&server).Error; err != nil {
				log.Printf("插入测试数据失败: %v", err)
			} else {
				log.Printf("成功插入测试数据: %s", server.Name)
			}
		}
	}

	log.Println("数据库初始化完成")
}

// CORS中间件
func corsMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")

		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}

		c.Next()
	}
}

// 获取服务器列表
func getServers(c *gin.Context) {
	var servers []Server
	var err error

	// 确保连接使用utf8mb4字符集
	if err := db.Exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci").Error; err != nil {
		log.Printf("警告: 获取服务器列表前设置字符集失败: %v", err)
	}

	if useRawSQL {
		// 使用原生SQL方式，确保字符集正确
		// 先确保连接字符集正确
		if err := db.Exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci").Error; err != nil {
			log.Printf("警告: 查询前设置字符集失败: %v", err)
		}
		
		sql := `SELECT id, name, ip, hostname, os, cpu, memory, disk, status, deploy_time, last_checkin, created_at, updated_at 
			 FROM servers ORDER BY id`
		err = db.Raw(sql).Scan(&servers).Error
	} else {
		// 使用gorm方式
		result := db.Find(&servers)
		err = result.Error
	}

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "获取服务器列表失败: " + err.Error()})
		return
	}
	c.JSON(http.StatusOK, servers)
}

// 创建新服务器
func createServer(c *gin.Context) {
	// 设置请求体编码为UTF-8
	c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 1048576)
	
	var server Server
	if err := c.ShouldBindJSON(&server); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// 设置默认值
	if server.Status == "" {
		server.Status = "running"
	}
	if server.DeployTime.IsZero() {
		server.DeployTime = time.Now()
	}
	server.LastCheckin = time.Now()
	
	// 确保CPU字段不为空
	if server.CPU == "" {
		server.CPU = "未知"
	}

	var err error
	
	// 确保连接使用utf8mb4字符集
	if err := db.Exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci").Error; err != nil {
		log.Printf("警告: 创建服务器前设置字符集失败: %v", err)
	}
	
	// 添加额外的字符集设置
	if err := db.Exec("SET character_set_client = utf8mb4").Error; err != nil {
		log.Printf("警告: 设置客户端字符集失败: %v", err)
	}
	if err := db.Exec("SET character_set_results = utf8mb4").Error; err != nil {
		log.Printf("警告: 设置结果字符集失败: %v", err)
	}
	if err := db.Exec("SET character_set_connection = utf8mb4").Error; err != nil {
		log.Printf("警告: 设置连接字符集失败: %v", err)
	}
	
	if useRawSQL {
		// 记录接收到的CPU值
		log.Printf("接收到的CPU值: %v", server.CPU)
		
		// 使用原生SQL方式，再次确保字符集正确
		if err := db.Exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci").Error; err != nil {
			log.Printf("警告: 创建记录前设置字符集失败: %v", err)
		}
		
		sql := `INSERT INTO servers (name, ip, hostname, os, cpu, memory, disk, status, deploy_time, last_checkin, created_at, updated_at) 
		 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`
		result := db.Exec(sql, server.Name, server.IP, server.Hostname, server.OS, server.CPU, 
			server.Memory, server.Disk, server.Status, server.DeployTime, server.LastCheckin)
		err = result.Error
		
		if err == nil {
				// 获取插入的ID，但不重新查询整个记录
				var id int64
				if err := db.Raw("SELECT LAST_INSERT_ID()").Scan(&id).Error; err != nil {
					log.Printf("警告: 获取插入ID失败: %v", err)
				} else {
					server.ID = uint(id)
					// 直接使用接收到的数据，不重新查询数据库
					log.Printf("插入成功，ID: %d，CPU值保持不变", id)
				}
			}
	} else {
		// 记录接收到的CPU值
		log.Printf("GORM模式 - 接收到的CPU值: %v", server.CPU)
		
		// 简化GORM操作，不使用事务
		// 直接使用GORM创建记录，但不重新查询
		tempServer := server // 保存原始数据
		if err := db.Create(&tempServer).Error; err != nil {
			err = err
		} else {
			// 只获取ID，保留原始的CPU值
			server.ID = tempServer.ID
			log.Printf("GORM插入成功，ID: %d，CPU值保持不变", server.ID)
		}
	}

	if err != nil {
		// 检查是否是唯一约束冲突
		if err.Error()[0:10] == "UNIQUE con" {
			c.JSON(http.StatusConflict, gin.H{"error": "服务器名称或IP已存在"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": "创建服务器失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusCreated, server)
}

// 获取单个服务器详情
func getServer(c *gin.Context) {
	id := c.Param("id")
	var server Server
	var err error

	if useRawSQL {
		// 使用原生SQL方式
		sql := `SELECT id, name, ip, hostname, os, cpu, memory, disk, status, deploy_time, last_checkin, created_at, updated_at 
				 FROM servers WHERE id = ?`
		err = db.Raw(sql, id).Scan(&server).Error
	} else {
		// 使用gorm方式
		result := db.First(&server, id)
		err = result.Error
	}

	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "服务器未找到"})
		return
	}
	c.JSON(http.StatusOK, server)
}

// 更新服务器信息
func updateServer(c *gin.Context) {
	id := c.Param("id")
	var server Server
	var err error

	// 检查服务器是否存在
	if useRawSQL {
		err = db.Raw("SELECT * FROM servers WHERE id = ?", id).Scan(&server).Error
	} else {
		err = db.First(&server, id).Error
	}

	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "服务器未找到"})
		return
	}

	var updateData Server
	if err := c.ShouldBindJSON(&updateData); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// 更新服务器信息
	updateData.LastCheckin = time.Now()
	updateData.UpdatedAt = time.Now()

	if useRawSQL {
		// 使用原生SQL方式
		// 构建动态SQL更新语句
		sql := "UPDATE servers SET last_checkin = ?, updated_at = NOW()"
		params := []interface{}{updateData.LastCheckin}

		if updateData.Name != "" {
			sql += ", name = ?"
			params = append(params, updateData.Name)
		}
		if updateData.IP != "" {
			sql += ", ip = ?"
			params = append(params, updateData.IP)
		}
		if updateData.Hostname != "" {
			sql += ", hostname = ?"
			params = append(params, updateData.Hostname)
		}
		if updateData.OS != "" {
			sql += ", os = ?"
			params = append(params, updateData.OS)
		}
		if updateData.CPU != "" {
			sql += ", cpu = ?"
			params = append(params, updateData.CPU)
		}
		if updateData.Memory != 0 {
			sql += ", memory = ?"
			params = append(params, updateData.Memory)
		}
		if updateData.Disk != 0 {
			sql += ", disk = ?"
			params = append(params, updateData.Disk)
		}
		if updateData.Status != "" {
			sql += ", status = ?"
			params = append(params, updateData.Status)
		}
		if !updateData.DeployTime.IsZero() {
			sql += ", deploy_time = ?"
			params = append(params, updateData.DeployTime)
		}

		sql += " WHERE id = ?"
		params = append(params, id)

		result := db.Exec(sql, params...)
		err = result.Error
		
		if err == nil {
			// 获取更新后的数据
			db.Raw("SELECT * FROM servers WHERE id = ?", id).Scan(&server)
		}
	} else {
		// 使用gorm方式
		// 使用Updates方法更新非零值字段
		result := db.Model(&server).Updates(updateData)
		err = result.Error

		if err == nil {
			// 获取更新后的数据
			db.First(&server, id)
		}
	}

	if err != nil {
		// 检查是否是唯一约束冲突
		if err.Error()[0:10] == "UNIQUE con" {
			c.JSON(http.StatusConflict, gin.H{"error": "服务器名称或IP已存在"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": "更新服务器失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, server)
}

// 删除服务器
func deleteServer(c *gin.Context) {
	id := c.Param("id")
	var result *gorm.DB
	var rowsAffected int64
	var err error

	if useRawSQL {
		// 使用原生SQL方式
		sql := "DELETE FROM servers WHERE id = ?"
		result = db.Exec(sql, id)
		err = result.Error
		if err == nil {
			rowsAffected = result.RowsAffected
		}
	} else {
		// 使用gorm方式
		result = db.Delete(&Server{}, id)
		err = result.Error
		rowsAffected = result.RowsAffected
	}

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "删除服务器失败: " + err.Error()})
		return
	}
	if rowsAffected == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "服务器未找到"})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "服务器删除成功"})
}
